import { hasPerm } from '@/config/acl'
import { Vue, Component, Prop } from 'vue-property-decorator'
import Transporter, { TransportItem } from './Transporter'
import { remote } from 'electron'
import path from 'path'
import { getUserDocs } from '@/api/doc'

export interface FileData {
  id: string;
  docId: number;
  type: 'dir' | 'file';
  name: string;
  status: 'pending' | 'downloading' | 'success' | 'fail' | 'pause';
  size: number;
  doneSize: number;
  lastDoneSize: number;
  localPath: string;
  errMsg?: string;
  speed?: number;
  contentType?: string;
  action?: 'pause' | 'remove' | 'start'
}

export interface DirRequestItem {
  docId: number;
  path: string;
  localPath: string;
  downloadId: string;
}

let index = 1

function genId () {
  return Date.now() + '' + (index++) + (Math.random() + '').slice(-4)
}

function getFiles (parentId: number) {
  return getUserDocs({ page: 0, size: 3000 }, parentId, true).then(data => {
    return (data?.content || []).filter(v => hasPerm('download', v))
  })
}

@Component
export default class Downloader extends Vue {
  queue: FileData[] = [
    // {
    //   id: '1',
    //   docId: 1,
    //   type: 'file',
    //   name: '测试文件.xlxs',
    //   status: 'pending',
    //   size: 129478,
    //   localPath: '',
    //   doneSize: 0,
    //   lastDoneSize: 0,
    //   speed: 1290
    // },
    // {
    //   id: '2',
    //   docId: 2,
    //   type: 'file',
    //   name: '测试文件234.xlxs',
    //   status: 'downloading',
    //   size: 129478,
    //   localPath: '',
    //   doneSize: 12345,
    //   lastDoneSize: 0,
    //   speed: 1290
    // },
    // {
    //   id: '3',
    //   docId: 3,
    //   type: 'file',
    //   name: '测试文件abc.xlxs',
    //   status: 'pause',
    //   size: 1294435355478,
    //   localPath: '',
    //   doneSize: 3123,
    //   lastDoneSize: 0,
    //   speed: 1290
    // },
    // {
    //   id: '4',
    //   docId: 4,
    //   type: 'file',
    //   name: '测试文件abc.xlxs',
    //   status: 'success',
    //   size: 129344478,
    //   localPath: '',
    //   doneSize: 123444,
    //   lastDoneSize: 0,
    //   speed: 1290
    // },
    // {
    //   id: '5',
    //   docId: 5,
    //   type: 'file',
    //   name: '测试文件abc.xlxs',
    //   status: 'fail',
    //   size: 1234,
    //   localPath: '',
    //   doneSize: 500,
    //   lastDoneSize: 0,
    //   speed: 1290
    // }
  ]

  dirRequestQueue: DirRequestItem[] = []

  maxDirRequestNum = 4

  currentDirRequestNum = 0

  transporter = new Transporter()

  add (rows: any[] = []) {
    if (rows.length < 1) return
    remote.dialog.showOpenDialog({
      properties: ['openDirectory']
    }).then(data => {
      if (!data?.canceled) {
        const target = data?.filePaths[0] || ''
        rows.forEach(row => {
          const item: FileData = {
            id: genId(),
            docId: row?.id,
            name: row.name,
            type: row.type,
            status: 'pending',
            localPath: target,
            size: 0,
            doneSize: 0,
            lastDoneSize: 0,
            speed: 0
          }
          this.queue.push(item)
          this.putInTransporter(item, row)
        })
      }
    })
  }

  pause (id: string) {
    const item = this.queue.find(v => v.id === id)
    if (item) item.action = 'pause'
    this.transporter.pause(id)
  }

  resume (id: string) {
    const item = this.queue.find(v => v.id === id)
    if (item) item.action = 'start'
    this.transporter.resume(id)
  }

  retry (id: string) {
    const item = this.queue.find(v => v.id === id)
    if (item) item.action = 'start'
    this.transporter.retry(id)
  }

  remove (id: string) {
    const item = this.queue.find(v => v.id === id)
    if (item) item.action = 'remove'
    this.transporter.remove(id)
    this.queue = this.queue.filter(v => v.id !== id)
  }

  removeAll () {
    this.queue.forEach(v => {
      v.action = 'remove'
    })
    this.queue = []
    this.dirRequestQueue = []
    this.currentDirRequestNum = 0
    this.transporter.removeAll()
  }

  private putInTransporter (data: FileData, row: any) {
    if (data.type === 'dir') {
      const item: DirRequestItem = {
        docId: row.id,
        path: row.name,
        localPath: data.localPath,
        downloadId: data.id
      }
      this.dirRequestQueue.push(item)
    } else {
      const item: TransportItem = {
        docId: data.docId,
        docName: data.name,
        localPath: path.resolve(data.localPath, data.name),
        downloadId: data.id,
        done: 0,
        size: row.size
      }
      this.transporter.pendingQueue.push(item)
    }
  }

  private run () {
    const fn = () => {
      const items = this.queue.filter(v => ['pending', 'downloading', 'pause', 'fail'].includes(v.status))
      items.forEach(v => {
        const status = this.transporter.getStatus(v.id)
        v.status = status
        if (status === 'downloading') {
          const p = this.transporter.getProgress(v.id)
          v.size = p.total || 0
          v.lastDoneSize = v.doneSize || 0
          v.doneSize = p.done || 0
          v.speed = v.doneSize - v.lastDoneSize
        }
      })
    }
    setInterval(fn, 1000)
  }

  private scheduleDirRequest () {
    const fn = () => {
      this.doDirAdd()
    }
    setInterval(fn, 1000)
  }

  private doDirAdd () {
    if (this.currentDirRequestNum >= this.maxDirRequestNum) return
    const item = this.dirRequestQueue.pop()
    if (!item) return
    const di = this.queue.find(v => v.id === item.downloadId)
    if (!di || di.action === 'remove') return
    this.currentDirRequestNum++
    getFiles(item.docId).then(data => {
      if (di.action === 'remove') return
      data.forEach(v => {
        if (v.type === 'dir') {
          const row: DirRequestItem = {
            docId: v.id,
            path: item.path + '/' + v.name,
            localPath: item.localPath,
            downloadId: item.downloadId
          }
          this.dirRequestQueue.push(row)
        } else {
          const row: TransportItem = {
            docId: v.id,
            docName: v.name,
            localPath: path.resolve(item.localPath, item.path, v.name),
            downloadId: item.downloadId,
            done: 0,
            size: v.size
          }
          if (di.action === 'pause') {
            this.transporter.pauseQueue.push(row)
          } else {
            this.transporter.pendingQueue.push(row)
          }
        }
      })
    }).finally(() => {
      const idx = this.dirRequestQueue.findIndex(v => v === item)
      if (idx >= 0) this.dirRequestQueue.splice(idx, 1)
      this.currentDirRequestNum = Math.max(0, this.currentDirRequestNum - 1)
    })
  }

  created () {
    this.run()
    this.scheduleDirRequest()
  }
}
